package ext.wxcp;

import cache.CacheHelper;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
import me.chanjar.weixin.cp.api.WxCpConfigStorage;
import java.io.File;
import java.io.Serializable;

/**
 * 可缓存的微信配置provider.
 */
public class CacheableWxCpConfigStorage implements WxCpConfigStorage, Serializable {

    private static final long serialVersionUID = -8865460578813109556L;

    protected volatile String corpId;
    protected volatile String corpSecret;
    protected volatile Boolean fromSuite;

    protected volatile String token;
    protected volatile String accessToken;
    protected volatile String aesKey;
    protected volatile Integer agentId;
    protected volatile String corpAppId;

    protected volatile long   expiresTime;
    protected volatile long   jsApiExpiresTime;

    protected volatile String oauth2redirectUri;

    protected volatile String http_proxy_host;
    protected volatile int    http_proxy_port;
    protected volatile String http_proxy_username;
    protected volatile String http_proxy_password;

    protected volatile File tmpDirFile;

    private String getAccessTokenCacheKey() {
        return "WxCpAccessToken_C" + corpId + "_A" + agentId;
    }
    private String getAccessTokenTimeOutCacheKey() {
        return "WxCpAccessTokenTimeOut_C" + corpId + "_A" + agentId;
    }

    private String getJsApiTicketCacheKey() {
        return "WxCpJsApiTicket_C" + corpId + "_A" + agentId;
    }
    private String getJsApiTicketTimeOutCacheKey() {
        return "WxCpJsApiTicketTimeOut_C" + corpId + "_A" + agentId;
    }

    public String getAccessToken() {
        return (String) CacheHelper.getCache(getAccessTokenCacheKey());
    }

    public boolean isAccessTokenExpired() {
        // 如果是suiteApp, 检查后，如果expired，就手工设置一次，直接返回false
        if (fromSuite) {
            if (checkCacheForAccessTokenExpired()) {
                // 使用应用套件的方式更新accessToken
                /*
                CorpApp corpApp = CorpApp.findById(getCorpAppId());
                Logger.info("read SuiteAccessToken: corpAppId=%s, cacheKey=%s, lastToken=%s", getCorpAppId(),
                        getAccessTokenCacheKey(), getAccessToken());
                String accessToken = WxCpSuiteHelper.getCorpAccessToken(corpApp.wxCorpId, corpApp.permanentCode);
                updateAccessToken(accessToken, 3600);
                */
            }
            return false;
        }
        return checkCacheForAccessTokenExpired();
    }

    private boolean checkCacheForAccessTokenExpired() {
        Long expireTime = CacheHelper.getCache(getAccessTokenTimeOutCacheKey(), Long.class);
        if (expireTime == null) expireTime = System.currentTimeMillis() - 100l;
        return System.currentTimeMillis() > expireTime || !CacheHelper.exists(getAccessTokenCacheKey());
    }

    public void expireAccessToken() {
        CacheHelper.delete(getAccessTokenCacheKey());
    }

    public synchronized void updateAccessToken(WxAccessToken accessToken) {
        updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
    }

    /**
     * 实现这个方法，把accessToken和expiresInSeconds放到Memcached，即可支持Memcached.
     */
    public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {
        CacheHelper.setCache(getAccessTokenCacheKey(), accessToken, (expiresInSeconds - 200) + "s");
        this.setExpiresTime(System.currentTimeMillis() + (long)(expiresInSeconds - 200) * 1000L);
        CacheHelper.setCache(getAccessTokenTimeOutCacheKey(), getExpiresTime());
    }

    @Override public String getJsapiTicket() {
        return (String) CacheHelper.getCache(getJsApiTicketCacheKey());
    }

    @Override public boolean isJsapiTicketExpired() {
        Long expireTime = CacheHelper.getCache(getJsApiTicketTimeOutCacheKey(), Long.class);
        if (expireTime == null) expireTime = System.currentTimeMillis() - 100l;
        return System.currentTimeMillis() > expireTime || !CacheHelper.exists(getJsApiTicketCacheKey());
    }

    @Override public void expireJsapiTicket() {
        CacheHelper.delete(getJsApiTicketCacheKey());
    }

    @Override public void updateJsapiTicket(String ticket, int expiresInSeconds) {
        CacheHelper.setCache(getJsApiTicketCacheKey(), ticket, (expiresInSeconds - 200) + "s");
        this.jsApiExpiresTime = (System.currentTimeMillis() + (long) (expiresInSeconds - 200) * 1000L);
        CacheHelper.setCache(getJsApiTicketTimeOutCacheKey(), this.jsApiExpiresTime);
    }

    public String getCorpId() {
        return this.corpId;
    }

    public String getCorpSecret() {
        return this.corpSecret;
    }

    public String getToken() {
        return this.token;
    }

    public long getExpiresTime() {
        return this.expiresTime;
    }

    public void setCorpId(String corpId) {
        this.corpId = corpId;
    }

    public void setCorpSecret(String corpSecret) {
        this.corpSecret = corpSecret;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public String getAesKey() {
        return aesKey;
    }

    public void setAesKey(String aesKey) {
        this.aesKey = aesKey;
    }

    public void setAccessToken(String accessToken) {
        updateAccessToken(accessToken, 3600);
    }

    public void setExpiresTime(long expiresTime) {
        this.expiresTime = expiresTime;
    }

    public Integer getAgentId() {
        return agentId;
    }

    public void setAgentId(Integer agentId) {
        this.agentId = agentId;
    }

    public Boolean getFromSuite() {
        return fromSuite;
    }

    public void setFromSuite(Boolean fromSuite) {
        this.fromSuite = fromSuite;
    }

    /**
     * Gets corpAppId.
     *
     * @return Value of corpAppId.
     */
    public String getCorpAppId() {
        return corpAppId;
    }

    /**
     * Sets new corpAppId.
     *
     * @param corpAppId New value of corpAppId.
     */
    public void setCorpAppId(String corpAppId) {
        this.corpAppId = corpAppId;
    }

    @Override
    public String getOauth2redirectUri() {
        return this.oauth2redirectUri;
    }

    @Override
    public String getHttpProxyHost() {
        return null;  //TODO: 删除此备注
    }

    @Override
    public int getHttpProxyPort() {
        return 0;  //TODO: 删除此备注
    }

    @Override
    public String getHttpProxyUsername() {
        return null;  //TODO: 删除此备注
    }

    @Override
    public String getHttpProxyPassword() {
        return null;  //TODO: 删除此备注
    }

    public void setOauth2redirectUri(String oauth2redirectUri) {
        this.oauth2redirectUri = oauth2redirectUri;
    }

    public String getHttp_proxy_host() {
        return http_proxy_host;
    }

    public void setHttp_proxy_host(String http_proxy_host) {
        this.http_proxy_host = http_proxy_host;
    }

    public int getHttp_proxy_port() {
        return http_proxy_port;
    }

    public void setHttp_proxy_port(int http_proxy_port) {
        this.http_proxy_port = http_proxy_port;
    }

    public String getHttp_proxy_username() {
        return http_proxy_username;
    }

    public void setHttp_proxy_username(String http_proxy_username) {
        this.http_proxy_username = http_proxy_username;
    }

    public String getHttp_proxy_password() {
        return http_proxy_password;
    }

    public File getTmpDirFile() {
        return tmpDirFile;
    }

    @Override
    public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
        return null;  //TODO: 删除此备注
    }

    public void setTmpDirFile(File tmpDirFile) {
        this.tmpDirFile = tmpDirFile;
    }

    public void setHttp_proxy_password(String http_proxy_password) {
        this.http_proxy_password = http_proxy_password;
    }

    @Override
    public String toString() {
        return "CacheableWxCpConfigStorage{" +
                "corpId='" + corpId + '\'' +
                ", corpSecret='" + corpSecret + '\'' +
                ", token='" + token + '\'' +
                ", aesKey='" + aesKey + '\'' +
                ", agentId='" + agentId + '\'' +
                ", expiresTime=" + expiresTime +
                ", http_proxy_host='" + http_proxy_host + '\'' +
                ", http_proxy_port=" + http_proxy_port +
                ", http_proxy_username='" + http_proxy_username + '\'' +
                ", http_proxy_password='" + http_proxy_password + '\'' +
                '}';
    }

}

